package com.example.musictutor.services;

import java.io.IOException;

import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.util.Log;

import com.example.musictutor.R;
import com.example.musictutor.activities.PlaySongActivity;
import com.example.musictutor.domain.Note;
import com.example.musictutor.domain.Song;
import com.example.musictutor.domain.SongNote;

public class RecordSong {

	public static int STATE_NOT_RECORDING = 0;
	public static int STATE_RECORDING = 1;

	private static RecordSong instance;

	private Song song;
	private int state;

	private int currentBeat;
	private int beatDuration;
	private int currentDuration;

	private MediaPlayer mediaPlayer;
	private Context context;

	private class BeatsRunnable extends Metronome implements Runnable {
		PlaySongActivity activity = null;

		public BeatsRunnable() {
			super(context);
		}
		
		@Override
		public void run() {
			activity = (PlaySongActivity) context;
			activity.runOnUiThread(new Runnable() {
				public void run() {
					KeyBoard.getInstance().setEnabled(true);
					// activity.setBackgroundDimmed(false);
				}
			});

			while (state == STATE_RECORDING) {

				if (currentBeat % 4 == 0)
					playMetronomeSound(true);
				else
					playMetronomeSound(false);

				try {
					Thread.sleep(beatDuration);
				} catch (InterruptedException e) {
					Log.e("RecordingSong", e.getStackTrace().toString());
				}

				stopMediaPlayer();
				currentBeat++;
			}

			Log.d("asdf", "beats thread ended");
			if (mediaPlayer != null) {
				mediaPlayer.release();
				mediaPlayer = null;
			}
		}

	};

	private class CountDownRunnable extends Metronome implements Runnable {
		PlaySongActivity activity = null;

		public CountDownRunnable() {
			super(context);
		}
		
		@Override
		public void run() {
			Log.d("asdf", "countdown thread started");
			int beatCount = 0;
			activity = (PlaySongActivity) context;

			while (beatCount < 8) {
				if (beatCount % 4 == 0)
					playMetronomeSound(true);
				else
					playMetronomeSound(false);

				if (beatCount == 7) {
					activity.runOnUiThread(new Runnable() {
						public void run() {
							KeyBoard.getInstance().setEnabled(true);
						}
					});
				}

				try {
					Thread.sleep(beatDuration);
				} catch (InterruptedException e) {
					Log.e("RecordingSong", e.getStackTrace().toString());
				}

				stopMediaPlayer();
				beatCount++;
			}

			Thread beatsThread = new Thread(new BeatsRunnable());
			beatsThread.start();
			Thread durationThread = new Thread(new DurationRunnable());
			durationThread.start();

			Log.d("asdf", "countdown thread ended");
		}
	}

	private class DurationRunnable implements Runnable {

		@Override
		public void run() {
			currentDuration = 0;

			while (state == STATE_RECORDING) {
				try {
					Thread.sleep(20);
				} catch (InterruptedException e) {
					Log.e("RecordingSong", e.getStackTrace().toString());
				}

				currentDuration += 20;
			}
		}

	}

	private RecordSong() {
		currentBeat = 0;
	}

	public static RecordSong getInstance() {
		if (instance == null)
			instance = new RecordSong();

		return instance;
	}

	public void setContext(Context context) {
		this.context = context;
	}

	public void startRecording(int tempo) {
		state = STATE_RECORDING;

		song = new Song();
		song.setTempo(tempo);

		currentBeat = 0;
		beatDuration = getBeatDuration();

		Thread countDownThread = new Thread(new CountDownRunnable());
		countDownThread.start();
	}

	public Song stopRecording() {
		state = STATE_NOT_RECORDING;

		Song newSong = song;
		currentBeat = 0;
		beatDuration = 0;

		return newSong;
	}

	private class AddNoteRunnable implements Runnable {

		private int runNoteDuration;
		private int runCurrentDuration;
		private Note runNote;

		public AddNoteRunnable(int noteDuration, int currentDuration, Note note) {
			runNoteDuration = noteDuration;
			runCurrentDuration = currentDuration;
			runNote = note;
		}

		@Override
		public void run() {
			SongNote songNote = new SongNote(runNote.getName(),
					runNote.getResourceId());

			int savedDuration = runCurrentDuration;
			int endPosition = savedDuration;// getScaledPosition(savedDuration);
			int startPosition = endPosition - runNoteDuration;// getScaledPosition(savedDuration
																// -
																// runNoteDuration);

			songNote.setStartPosition(startPosition);
			songNote.setEndPosition(endPosition);

			Log.d("Recording", "Note = " + runNote.getName());
			Log.d("Recording", "CurrentDuration = " + savedDuration);
			Log.d("Recording", "Start Pos = " + startPosition);
			Log.d("Recording", "End Pos = " + endPosition);
			Log.d("Recording", "Duration = " + runNoteDuration);
			Log.d("Recording", "--------");

			song.addNote(songNote);
		}

	}

	public void AddNote(Note note, int duration) {
		if (state == STATE_RECORDING) {
			Thread thread = new Thread(new AddNoteRunnable(duration,
					currentDuration, note));
			thread.start();
		}
	}

	private int getScaledPosition(int position) {
		float sixteenthNote = beatDuration / 2;

		float factor = Math.round(position / sixteenthNote);

		return (int) (sixteenthNote * factor);
	}

	/*private void playMetronomeSound(boolean first) {
		if (first) {
			playMetronomeFirstBeat();
		} else {
			stopMediaPlayer();
			if (mediaPlayer == null) {
				mediaPlayer = new MediaPlayer();

				try {
					AssetFileDescriptor afd = null;
					afd = context.getResources().openRawResourceFd(
							R.raw.metronome);

					if (afd != null && mediaPlayer != null) {
						mediaPlayer.setDataSource(afd.getFileDescriptor(),
								afd.getStartOffset(), afd.getDeclaredLength());
						mediaPlayer
								.setOnPreparedListener(new OnPreparedListener() {

									@Override
									public void onPrepared(MediaPlayer mp) {
										mp.setVolume(0.25f, 0.25f);
										mp.start();
									}
								});
						mediaPlayer.setOnErrorListener(new OnErrorListener() {

							@Override
							public boolean onError(MediaPlayer mp, int what,
									int extra) {
								Log.e("Hein MediaPlayer",
										"ErrorListener Triggered");
								if (mp != null) {
									mp.release();
									mp = null;
									mediaPlayer = null;
								}
								return false;
							}
						});
						mediaPlayer.prepareAsync();
					}

				} catch (IllegalArgumentException e) {
					Log.e("Player", e.getStackTrace().toString());
				} catch (SecurityException e) {
					Log.e("Player", e.getStackTrace().toString());
				} catch (IllegalStateException e) {
					Log.e("Player", e.getStackTrace().toString());
				} catch (IOException e) {
					Log.e("Player", e.getStackTrace().toString());
				}
			} else {
				mediaPlayer.start();
			}
		}
	}

	private void playMetronomeFirstBeat() {
		MediaPlayer mp = new MediaPlayer();

		try {
			AssetFileDescriptor afd = null;

			afd = context.getResources().openRawResourceFd(R.raw.metronome2);

			if (afd != null && mp != null) {
				mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(),
						afd.getDeclaredLength());
				mp.setOnPreparedListener(new OnPreparedListener() {

					@Override
					public void onPrepared(MediaPlayer mp) {
						mp.setVolume(0.25f, 0.25f);
						mp.start();
					}
				});
				mp.setOnErrorListener(new OnErrorListener() {

					@Override
					public boolean onError(MediaPlayer mp, int what, int extra) {
						Log.e("Hein MediaPlayer", "ErrorListener Triggered");
						if (mp != null) {
							mp.release();
							mp = null;
						}
						return false;
					}
				});
				mp.setOnCompletionListener(new OnCompletionListener() {

					@Override
					public void onCompletion(MediaPlayer mp) {
						if (mp != null) {
							mp.release();
							mp = null;
						}
					}
				});
				mp.prepareAsync();
			}

		} catch (IllegalArgumentException e) {
			Log.e("Player", e.getStackTrace().toString());
		} catch (SecurityException e) {
			Log.e("Player", e.getStackTrace().toString());
		} catch (IllegalStateException e) {
			Log.e("Player", e.getStackTrace().toString());
		} catch (IOException e) {
			Log.e("Player", e.getStackTrace().toString());
		}
	}

	private void stopMediaPlayer() {
		if (mediaPlayer != null) {

			if (mediaPlayer.isPlaying())
				mediaPlayer.stop();

			mediaPlayer.seekTo(0);
		}
	}*/

	private int getBeatDuration() {
		float bps = song.getTempo() / 60;
		float miliPerBeat = (1 / bps) * 1000;

		return (int) miliPerBeat;
	}

	public int getState() {
		return state;
	}

	public void setState(int state) {
		this.state = state;
	}

}
